<!DOCTYPE html>
<html prefix="og: http://ogp.me/ns# article: http://ogp.me/ns/article#
" lang="zh_cn">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>推荐启用C#特性Nullable reference types | vitamind3 竹里馆</title>
<link href="../../assets/css/all-nocdn.css" rel="stylesheet" type="text/css">
<link href="../../assets/css/ipython.min.css" rel="stylesheet" type="text/css">
<link href="../../assets/css/nikola_ipython.css" rel="stylesheet" type="text/css">
<meta name="theme-color" content="#5670d4">
<meta name="generator" content="Nikola (getnikola.com)">
<link rel="alternate" type="application/rss+xml" title="RSS" hreflang="zh_cn" href="../../rss.xml">
<link rel="canonical" href="https://vitamind3.gitee.io/posts/tui-jian-qi-yong-cte-xing-nullable-reference-types/">
<!--[if lt IE 9]><script src="../../assets/js/html5.js"></script><![endif]--><meta name="author" content="vitamind3">
<link rel="prev" href="../zi-dong-sheng-cheng-lei-shi-xian-jie-kou/" title="自动生成类实现接口" type="text/html">
<link rel="next" href="../tiao-zhan-1xiao-shi-pythonbian-ma-ti-qu-he-suan-bao-gao-shu-ju/" title="挑战1小时python编码提取核酸报告数据" type="text/html">
<meta property="og:site_name" content="vitamind3 竹里馆">
<meta property="og:title" content="推荐启用C#特性Nullable reference types">
<meta property="og:url" content="https://vitamind3.gitee.io/posts/tui-jian-qi-yong-cte-xing-nullable-reference-types/">
<meta property="og:description" content="在最近半年上了新项目后开始用上了C# 8.0的新特性 Nullable reference types 。挺有意思的，记录一下。
官方文档见 Nullable reference types | Microsoft Docs 。Nullable reference types 是给开发者使用的工具，开发者能用来标记引用类型是否可为null，编译器会对这些类型进行检查 ，如果有赋null值的情况，就">
<meta property="og:type" content="article">
<meta property="article:published_time" content="2022-03-31T21:12:35+08:00">
</head>
<body>
<a href="#content" class="sr-only sr-only-focusable">跳到主内容</a>

<!-- Menubar -->

<nav class="navbar navbar-expand-md static-top mb-4
navbar-dark
bg-dark
"><div class="container">
<!-- This keeps the margins nice -->
        <a class="navbar-brand" href="../../">

            <span id="blog-title">vitamind3 竹里馆</span>
        </a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#bs-navbar" aria-controls="bs-navbar" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>

        <div class="collapse navbar-collapse" id="bs-navbar">
            <ul class="navbar-nav mr-auto">
<li class="nav-item">
<a href="../../pages/introduction" class="nav-link">欢迎</a>
                </li>
<li class="nav-item">
<a href="../../archive.html" class="nav-link">文章归档</a>
                </li>
<li class="nav-item">
<a href="../../categories/" class="nav-link">分类</a>
                </li>
<li class="nav-item">
<a href="../../rss.xml" class="nav-link">RSS 源</a>

                
            </li>
</ul>
<ul class="navbar-nav navbar-right"></ul>
</div>
<!-- /.navbar-collapse -->
    </div>
<!-- /.container -->
</nav><!-- End of Menubar --><div class="container" id="content" role="main">
    <div class="body-content">
        <!--Body content-->
        
        
        
<article class="post-text h-entry hentry postpage" itemscope="itemscope" itemtype="http://schema.org/Article"><header><h1 class="p-name entry-title" itemprop="headline name"><a href="." class="u-url">推荐启用C#特性Nullable reference types</a></h1>

        <div class="metadata">
            <p class="byline author vcard p-author h-card"><span class="byline-name fn p-name" itemprop="author">
                    vitamind3
            </span></p>
            <p class="dateline">
            <a href="." rel="bookmark">
            <time class="published dt-published" datetime="2022-03-31T21:12:35+08:00" itemprop="datePublished" title="2022-03-31 21:12">2022-03-31 21:12</time></a>
            </p>
            

        </div>
        

    </header><div class="e-content entry-content" itemprop="articleBody text">
    <div>
<p>在最近半年上了新项目后开始用上了C# 8.0的新特性 Nullable reference types 。挺有意思的，记录一下。</p>
<p>官方文档见 <a href="https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references">Nullable reference types | Microsoft Docs</a> 。Nullable reference types 是给开发者使用的工具，开发者能用来标记引用类型是否可为null，编译器会对这些类型进行检查 ，如果有赋null值的情况，就产生警告。这依然是静态类型语言的优点，即能在编译期尽可能多的排除潜在的问题。</p>
<!-- TEASER_END -->

<h4>启用NRT的方法</h4>
<ul>
<li>全局启用：VS2022打开项目/项目属性/生成/常规/可为Null的类型。你要是觉得用图形界面太LOW，不能显示出自己精通底层原理，也可以直接手改csproj文件。</li>
<li>部分启用：<code>#nullable</code>
</li>
</ul>
<h4>NRT 语法</h4>
<p>基础的语法很简单，<code>?</code>和<code>!</code>，如下：</p>
<pre class="code literal-block"><span></span><code>// 在引用类型后加?表示这个实例可为null
MyClass? MyInstance = null;
// 不加?则表示此类型不能为null，但使用!可抑制编译器产生警告。
MyClass AnotherInstance = null!;
</code></pre>

<p>另外也可使用标注<code>AllowNull</code>,<code>MaybeNull</code>等。</p>
<h4>什么时候使用<code>!</code>
</h4>
<p>什么时候需要加<code>?</code>很好确定。但什么时候使用 <code>!</code> 呢？大部分情况下如果没使用<code>?</code> ，则尽量不要使用<code>!</code> 。因为不用<code>?</code>就意味着此变量不可为null。但总有一些特殊情况，需要用到。</p>
<p>ASP.NET里如果使用了IoC，属性以注入的方式获得初始值。为了在定义属性时给个null的初值 ，此时就要用<code>null!</code>。</p>
<p>编译器能智能，会根据if等判断推测出NRT变量是否为null，但有一些情况推测不出来，例如：</p>
<pre class="code literal-block"><span></span><code><span class="k">void</span> <span class="nf">method</span><span class="p">(</span><span class="kt">int?</span> <span class="n">a</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// 如果这里使用的是if对a为null的情况做了判断，</span>
    <span class="c1">// 则后面即会认为a为非null。</span>
    <span class="c1">//if(a is null){ ... ; return;}</span>
    <span class="c1">// 但如果不是if，而是自定义的函数，则编译器无法判断。</span>
    <span class="c1">// 如果a为null，则抛出异常。</span>
    <span class="n">throw_if_arg_is_null</span><span class="p">(</span><span class="n">a</span><span class="p">);</span>
    <span class="c1">// 此时a肯定不是null，故使用!指定。</span>
    <span class="n">calc</span><span class="p">(</span><span class="n">a</span><span class="p">!);</span>
<span class="p">}</span>
</code></pre>

<h4>模板中使用<code>?</code>
</h4>
<p>第一眼看到NRT就觉得这是个好东西，但和模板扯上关系后，情况就复杂了。</p>
<p>例如一个泛型：</p>
<pre class="code literal-block"><span></span><code><span class="k">class</span> <span class="n">MyClass</span><span class="s">&lt;T&gt;</span>
<span class="s">{</span>
<span class="s">private List&lt;T&gt;</span> <span class="n">MyList</span>;
}
</code></pre>

<p>那么如果允许MyList中元素为空，用以下哪种方式？</p>
<p>方式一：在泛型内部定义时指定<code>?</code></p>
<pre class="code literal-block"><span></span><code><span class="k">class</span> <span class="n">MyClass</span><span class="s">&lt;T&gt;</span>
<span class="s">{</span>
<span class="s">private List&lt;T?&gt;</span> <span class="n">MyList</span>;
}

<span class="n">MyClass</span><span class="s">&lt;string&gt;</span> <span class="k">my</span>;
</code></pre>

<p>方式二：</p>
<pre class="code literal-block"><span></span><code><span class="k">class</span> <span class="n">MyClass</span><span class="s">&lt;T&gt;</span>
<span class="s">{</span>
<span class="s">private List&lt;T&gt;</span> <span class="n">MyList</span>;
}
<span class="n">MyClass</span><span class="s">&lt;string?&gt;</span> <span class="k">my</span>;
</code></pre>

<p>两种方式从语法上都最是OK的，都能编译通过。怎样取舍需要结合具体场景的需求考虑。</p>
<p>另外NRT在C# 8.0版后也在不断改进中，例如上面的方式一，在传入引用时，成员变为NRT类型，但如果传入的是<code>int?</code>则仍然是<code>List&lt;T?&gt;</code>，这一点是在之后的某个版本中改进的。</p>
<p>还有就是涉及使用 <code>default()</code> 的泛型，这里不再细说了。</p>
<h4>Fody.RuntimeNullables</h4>
<p>上一篇BLOG《推荐Fody》说到了 Fody.RuntimeNullables 插件。如果启用了NRT，那么强烈推荐同时搭配使用  Fody.RuntimeNullables 。这个插件的作用是为代码中的 NRT 参数添加运行时NULL检查，如果为null则会抛出异常。</p>
</div>
    </div>
    <aside class="postpromonav"><nav><ul class="pager hidden-print">
<li class="previous">
                <a href="../zi-dong-sheng-cheng-lei-shi-xian-jie-kou/" rel="prev" title="自动生成类实现接口">上一篇文章</a>
            </li>
            <li class="next">
                <a href="../tiao-zhan-1xiao-shi-pythonbian-ma-ti-qu-he-suan-bao-gao-shu-ju/" rel="next" title="挑战1小时python编码提取核酸报告数据">下一篇文章</a>
            </li>
        </ul></nav></aside></article><!--End of body content--><footer id="footer">
            Contents ©         <a href="https://vitamind3.gitee.io/">vitamind3</a> - Powered by         <a href="https://getnikola.com" rel="nofollow">Nikola</a>         
            
            
        </footer>
</div>
</div>


        <script src="../../assets/js/all-nocdn.js"></script><script>
    baguetteBox.run('div#content', {
        ignoreClass: 'islink',
        captions: function(element){var i=element.getElementsByTagName('img')[0];return i===undefined?'':i.alt;}});
    </script><script>
var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?09027755f7478e129aec2cdd3acf9a4c";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>
